/**
 * @param {Flickr.PhotoExif.photo} api
 * @constructor
 */
function Exif(api)
{
	"use strict";

	/** @type {Exif} */
	var _exif = this;

	/** @type {String} */
	this.software = null;

	/** @type {String} */
	this.copyright = null;

	/**
	 * @type {Object.<String>}
	 */
	this.camera =
	{
		make: null,
		model: null
	};

	/**
	 * @type {Object}
	 */
	this.settings =
	{
		whiteBalance: null,
		mode: null,
		/** @type {Number} */
		ISO: null
	};

	this.lens =
	{
		model: null,
		/** @type {Number} */
		aperture: null,
		/** @type {Number} */
		maxAperture: null,
		/** @type {Number} */
		focalLength: null,
		/** @type {Number} */
		focalLengthIn35mm: null
	};

	this.exposure =
	{
		mode: null,
		compensation: null,
		time: null
	};

	/**
	 * @type {Object.<Date>}
	 */
	this.dates =
	{
		created: null,
		original: null,
		modified: null
	};

	function init()
	{
		var ts = 'IFD0';

		_exif.software = normalizeSoftware(getRawValue(ts, 'Software'));
		_exif.camera.make = getRawValue(ts, 'Make');
		_exif.camera.model = normalizeCamera(getRawValue(ts, 'Model'));

		ts = 'ExifIFD';

		_exif.exposure.time = getRawValue(ts, 'ExposureTime');
		_exif.exposure.mode = getRawValue(ts, 'ExposureProgram');
		_exif.exposure.compensation = normalizeCompensation(getRawValue(ts, 'ExposureCompensation'));

		_exif.settings.ISO = Format.parseNumber(getRawValue(ts, 'ISO'));
		_exif.settings.mode = getRawValue(ts, 'ExposureMode');
		_exif.settings.whiteBalance = getRawValue(ts, 'WhiteBalance');

		_exif.lens.aperture = normalizeAperture(getRawValue(ts, 'FNumber'));
		_exif.lens.maxAperture = Format.parseNumber(getRawValue(ts, 'MaxApertureValue'));
		_exif.lens.focalLength = Format.parseNumber(getRawValue(ts, 'FocalLength'));
		_exif.lens.focalLengthIn35mm = Format.parseNumber(getRawValue(ts, 'FocalLengthIn35mmFormat'));
		_exif.lens.model = normalizeLens(getRawValue(ts, 'LensModel'));

		ts = 'IPTC';

		_exif.copyright = getRawValue(ts, 'CopyrightNotice');

		api = null;
	}

	/**
	 * @param {String} raw
	 * @return {String}
	 */
	function normalizeCompensation(raw)
	{
		return raw.replace(/(\d)\s*\/\s*(\d{1,2})/, '<span class="fraction"><sup>$1</sup>&frasl;<sub>$2</sub></span>');
	}

	/**
	 * @param {String} raw
	 * @return {String}
	 */
	function normalizeSoftware(raw)
	{
		return raw.replace(/\s*\(Windows\)/gi, '');
	}

	/**
	 * @param {String} raw
	 * @return {String}
	 */
	function normalizeAperture(raw)
	{
		var a = Format.parseNumber(raw);
		// defective firmware recorded aperture 1
		return (a == 1) ? NaN : a;
	}

	/**
	 * Friendlier camera name
	 * @param {String} raw
	 * @return {String}
	 */
	function normalizeCamera(raw)
	{
		switch (raw)
		{
			case 'GalaxyNexus': return 'Galaxy Nexus phone';
			default: return raw.replace('NIKON', 'Nikon');
		}
	}

	/**
	 * Friendlier lens name
	 * @param {String} raw
	 * @return {String}
	 */
	function normalizeLens(raw)
	{
		switch(raw)
		{
			case '58.0 mm f/1.4': return 'Voigtl&auml;nder Nokton 58mm f/1.4 SL II';
			case '35.0 mm f/2.0': return 'Zeiss Distagon T* 35mm f/2 ZF.2';
			case '100.0 mm f/2.0': return 'Zeiss Makro-Planar T* 100mm f/2 ZF.2';
			case '14.0 mm f/2.8': return 'Samyang 14mm f/2.8';
			case '24.0-70.0 mm f/2.8': return 'Nikkor 24&ndash;70mm f/2.8G';
			case '14.0-24.0 mm f/2.8': return 'Nikkor 14&ndash;24mm f/2.8G';
			case '10.0-20.0 mm f/4.0-5.6': return 'Sigma 10&ndash;20mm f/4.0&ndash;5.6';
			case '90.0 mm f/2.8': return 'Tamron 90mm f/2.8 SP AF Di';
			case '150.0 mm f/2.8': return 'Sigma 150mm f/2.8';
			case '18.0-200.0 mm f/3.5-5.6': return 'Nikkor 18&ndash;200mm f/3.5&ndash;5.6G';
			case '70.0-200.0 mm f/2.8': return 'Nikkor 70&ndash;200mm f/2.8G';
			case '50.0 mm f/1.4': return 'Sigma 50mm f/1.4';
			case '17.0-55.0 mm f/2.8': return 'Nikkor 17&ndash;55mm f/2.8G';
			case '180.0 mm f/2.8': return 'Nikkor 180mm f/2.8D';
			case '24.0 mm f/3.5': return 'Nikkor 24mm f/3.5D PC-E';
			default: return raw.replace('NIKKOR', 'Nikkor');
		}
	}

	/**
	 * @param {String} space TagSpace
	 * @param {String} key Tag
	 * @return {String}
	 */
	function getRawValue(space, key)
	{
		/** @type {Flickr.Exif} */
		var item = null;

		for (var i in api.exif)
		{
			item = api.exif[i];
			if (item.tag == key && item.tagspace == space) { return item.raw._content; }
		}
		return null;
	}

	init();
}
